import ast
import inspect
import re
import unittest


class EntrySet:
    def __init__(self, k, v):
        self.key = k
        self.value = v


class DictAdapter:
    def __init__(self, o: dict):
        self.inner_map = o

    def items(self):
        for k in self.inner_map:
            yield EntrySet(k, self.inner_map[k])


class StrAdapter:
    def __init__(self, s: str):
        self.inner_str = s

    def length(self):
        return len(self.inner_str)

    def substring(self, start_pos, stop_pos=None):
        if stop_pos is not None:
            return self.inner_str[start_pos: stop_pos]
        else:
            return self.inner_str[start_pos:]

    def toLowerCase(self):
        return self.inner_str.lower()

    def toUpperCase(self):
        return self.inner_str.upper()

    def __eq__(self, other):
        if isinstance(other, StrAdapter):
            return self.inner_str == other.inner_str
        else:
            return False


class BuiltinFunctions:
    @staticmethod
    def match_whole(pat, s) -> bool:
        return re.match('^%s$' % pat, s) is not None

    @staticmethod
    def get_iterable(o):
        if isinstance(o, list):
            return o
        elif isinstance(o, dict):
            return DictAdapter(o).items()
        else:
            return o

    @staticmethod
    def implicit_convert(o):
        if isinstance(o, str):
            return StrAdapter(o)
        else:
            return o

    @staticmethod
    def cstyle_div(a, b):
        if isinstance(a, int) and isinstance(b, int):
            return a // b
        else:
            return a / b


def build_call_func_node(func_name, arg_nodes):
    return ast.Call(func=ast.Name(id=func_name, ctx=ast.Load()), args=arg_nodes, keywords=[])


def prepare_builtin_funcs(run_ctx: dict):
    funcs = [x for x in inspect.getmembers(BuiltinFunctions, lambda c: inspect.isfunction(c))]
    for func_name, func in funcs:
        run_ctx[func_name] = func


class PyAdapterTest(unittest.TestCase):
    def test_dict_adapter(self):
        dict = DictAdapter({1: "china", 2: "usa"})
        key_set = set()
        for item in dict.items():
            key_set.add(item.key)
        self.assertEqual(key_set, set([1, 2]))

    def test_name_equal(self):
        self.assertEqual(BuiltinFunctions.get_iterable.__name__, 'get_iterable')

    def test_prepare_builtin_funcs(self):
        m = {}
        prepare_builtin_funcs(m)
        self.assertTrue('get_iterable' in m)
        self.assertTrue('match_whole' in m)


if __name__ == '__main__':
    unittest.main()
